﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Web;

namespace ScrumTable.Common
{
    #region Usings

    using System;
    using ScrumTable.Common.Properties;

    #endregion

    /// <summary>
    /// Contains the global utilities for the Type class.
    /// </summary>
    public static class TypeUtil
    {
        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        private const string NullableEnding = "?";
        private static readonly LocalDataStoreSlot DefaultInstancesSolt = Thread.GetNamedDataSlot("DefaultInstances");

        private static IDictionary<Type, object> DefaultInstances
        {
            get
            {
                IDictionary<Type, object> data = (IDictionary<Type, object>)Thread.GetData(DefaultInstancesSolt);

                if (data == null)
                {
                    data = new Dictionary<Type, object>();
                    Thread.SetData(DefaultInstancesSolt, data);
                }
                return data;
            }
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Converts the given type name into a CLR Type. This method checks
        /// if the given type is a nullable type which ends with a '?'.
        /// </summary>
        /// <param name="typeName">Specifies the type name as string.</param>
        /// <returns>Returns the retrieved type.</returns>
        public static Type GetType(string typeName)
        {
            PreCondition.AssertNotNullOrEmpty(typeName, "typeName");
            const char typeSeparator = ',';

            string[] typeNames = typeName.Split(
                new[] { typeSeparator },
                StringSplitOptions.RemoveEmptyEntries);

            if (typeNames.Length > 0 && typeNames[0].EndsWith(NullableEnding))
            {
                typeNames[0] = typeNames[0].Substring(0, typeNames[0].Length - NullableEnding.Length);
                
                return typeof (Nullable<>).MakeGenericType(
                    new[]
                        {
                            Type.GetType(string.Join(typeSeparator.ToString(), typeNames), true, true)
                        });
            }
            return Type.GetType(typeName, true, true);
        }

        /// <summary>
        /// Creates a default instance of the given input type.
        /// </summary>
        /// <param name="input">Specifies the left hand instance.</param>
        /// <returns>Returns the default instance of the type.</returns>
        public static object GetDefault(this Type input)
        {
            PreCondition.AssertNotNull(input, "input");

            if (input.IsValueType)
            {
                if (!DefaultInstances.ContainsKey(input))
                {
                    DefaultInstances[input] = Activator.CreateInstance(input);
                }
                return DefaultInstances[input];
            }
            return null;
       }

        #endregion
    }
}
